package com.weihong.demo.trade;

import com.futu.openapi.FTAPI_Conn;
import com.futu.openapi.FTAPI_Conn_Trd;
import com.futu.openapi.FTSPI_Conn;
import com.futu.openapi.FTSPI_Trd;
import com.futu.openapi.pb.TrdCommon;
import com.futu.openapi.pb.TrdGetPositionList;
import com.futu.openapi.pb.TrdUnlockTrade;
import com.weihong.demo.evn.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PositionService implements FTSPI_Conn, FTSPI_Trd {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final FTAPI_Conn_Trd trd = new FTAPI_Conn_Trd();

    public volatile boolean unlockDone = false;

    public volatile boolean isConnected = false;
    public volatile boolean right = true;
    public volatile boolean positionDone = false;
    volatile int trdEnv;
    volatile long trdAcc;

    public volatile Map<String, TrdCommon.Position> result = null;

    public void initCon() {
        if (isConnected) {
            return;
        }

        synchronized (PositionService.class) {
            if (isConnected) {
                return;
            }

            trd.setClientInfo("Positon", 3);  //设置客户端信息
            trd.setConnSpi(this);  //设置连接相关回调
            trd.setTrdSpi(this);   //设置交易相关回调
            trd.initConnect(Config.opendIP, (short) Config.opendPort, false);
            while (!isConnected) {
                logger.info("waiting for connect of postition");
                Config.sleepsec(1);
            }
        }
    }

    @Override
    public void onInitConnect(FTAPI_Conn client, long errCode, String desc) {
        if (errCode != 0) {
            logger.error("Trd onInitConnect: ret={} desc={} connID={}", errCode, desc, client.getConnectID());
            right = false;
        } else {
            isConnected = true;
        }
    }

    //解锁交易
    public Map<String, TrdCommon.Position> getpositionMap(int trdEnv, long trdAcc, String pwdMd5) {
        initCon();
        unlockDone = false;
        positionDone = false;

        this.trdAcc = trdAcc;
        this.trdEnv = trdEnv;

        TrdUnlockTrade.C2S c2s = TrdUnlockTrade.C2S.newBuilder()
                .setUnlock(true)
                .setPwdMD5(pwdMd5)
                .setSecurityFirm(TrdCommon.SecurityFirm.SecurityFirm_FutuSecurities.getNumber())
                .build();
        TrdUnlockTrade.Request req = TrdUnlockTrade.Request.newBuilder().setC2S(c2s).build();
        trd.unlockTrade(req);

        while (!positionDone) {
            logger.info("waiting for position");
            Config.sleepsec(1);
        }

        return result;
    }

    @Override
    public void onReply_UnlockTrade(FTAPI_Conn client, int nSerialNo, TrdUnlockTrade.Response rsp) {
        if (rsp.getRetType() != 0) {
            logger.error("UnlockTrade fail when get position with error: {}", rsp.getErrCode() + rsp.getRetType() + rsp.getRetMsg());
            right = false;
            return;
        }
        getPosition(trdEnv, trdAcc);
    }

    private void getPosition(int trdEnv, long trdAcc) {
        TrdCommon.TrdHeader header = TrdCommon.TrdHeader.newBuilder().setTrdEnv(trdEnv).setAccID(trdAcc).setTrdMarket(TrdCommon.TrdMarket.TrdMarket_HK_VALUE).build();
        TrdGetPositionList.C2S c2s = TrdGetPositionList.C2S.newBuilder().setHeader(header).build();
        TrdGetPositionList.Request req = TrdGetPositionList.Request.newBuilder().setC2S(c2s).build();
        trd.getPositionList(req);
    }

    @Override
    public void onReply_GetPositionList(FTAPI_Conn client, int nSerialNo, com.futu.openapi.pb.TrdGetPositionList.Response rsp) {
        if (rsp.getRetType() != 0) {
            logger.error("onReply_GetPositionList error: {}", rsp.getErrCode() + rsp.getRetType() + rsp.getRetMsg());
            right = false;
            positionDone = true;
            return;
        }
        List<TrdCommon.Position> positionList = rsp.getS2C().getPositionListList();
        result = new HashMap<>();
        for (TrdCommon.Position position : positionList) {
            result.put(position.getCode(), position);
        }
        if (result.isEmpty()) {
            logger.info("position is empty");
        }
        positionDone = true;
    }

    public void close() {
        trd.close();
    }
}
